package com.eduagent.xwqeduagent.app.teacher.MultimodalGeneration;

import cn.hutool.core.util.ObjectUtil;
import com.eduagent.xwqeduagent.adviser.MyLoggerAdvisor;
import com.eduagent.xwqeduagent.app.agent.GenerateMindMap;
import com.eduagent.xwqeduagent.constant.FileConstant;
import com.eduagent.xwqeduagent.constant.prompt.*;
import com.eduagent.xwqeduagent.model.entity.CourseOutline;
import com.eduagent.xwqeduagent.model.vo.*;
import com.eduagent.xwqeduagent.rag.QueryRewriter;
import com.eduagent.xwqeduagent.rag.QueryTranslation;
import com.eduagent.xwqeduagent.service.FileService;
import com.eduagent.xwqeduagent.utils.CosUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.api.Advisor;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonProcessingException;

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY;

/**
 * 多模态教师资源生成app
 */
@Component
@Slf4j
public class MultiModGeneration {

    private final ChatClient chatClient;

    @Resource
    private QueryRewriter queryRewriter;

    @Resource
    private QueryTranslation queryTranslation;

    @Resource
    private ToolCallback[] allTools;

    @Resource
    private GenerateMindMap generateMindMap;

    @Resource
    private ToolCallbackProvider toolCallbackProvider;

    @Resource
    private Advisor loveAppRagCloudAdvisor;

    @Resource
    private FileService fileService;

    @Resource
    private CosUtils cosUtils;


    /**
     * 初始化教师端资源生成和AI助手客户端
     */
    public MultiModGeneration(ChatModel dashscopeChatModel) {

        String schoolteacherPrompt = TeaMulGenerateSystem.TEACHER_PROMPT;
        chatClient = ChatClient.builder(dashscopeChatModel)
                .defaultSystem(schoolteacherPrompt)
                .defaultAdvisors(
                        //自定义日志Advisor，可以按需开启
                        new MyLoggerAdvisor()
                        //自定义 Re2推理增强 Advisor，可以按需开启
                        //new ReReadingAdvisor(),
                        //new SensitiveWordAdvisor()
                )
                .build();
    }


    /**
     * 多模态大模型课程大纲生成
     *   @param classname  课程大纲名称
     *   @param sessionId 会话id
     *   @return 大模型的回答
     */
    public CourseOutline GenerateClassOutline(String classname, String sessionId) {

        String courseReference = CourseReference.SYSTEM_PROMPT;
        CourseOutline courseOutline = chatClient
                .prompt()
                .system("请根据知识库中关于TensorFlow Lite、TensorFlow.js、嵌入式Python的教学资料，生成一门融合这三项技术的完整教学大纲，每章有标题，每章下有小节，结构为 Map<String, List<String>>。内容参考：" + courseReference)
                .user(classname)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 20))
                .advisors(loveAppRagCloudAdvisor)
                // 开启日志，便于观察效果
                .advisors(new MyLoggerAdvisor())
                .tools(allTools)
                .call()
                .entity(CourseOutline.class);

        System.out.println(courseReference);

        // TODO: 2025/5/20
        String userId = "18974901186";

        // 序列化为JSON字符串
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            String json = objectMapper.writeValueAsString(courseOutline);

            // 检查数据是否有效，防止使用错误数据生成思维导图
            if (isValidCourseOutline(courseOutline)) {
                log.info("课程大纲数据有效，开始生成思维导图");
                MindMapResultVO mindMapResultVO = generateMindMap.generateMindMap(json, userId, sessionId);
                log.info("思维导图生成结果{}", mindMapResultVO);

                // 更新课程大纲的思维导图URL
                if (mindMapResultVO != null && "success".equalsIgnoreCase(mindMapResultVO.getStatus())) {
                    courseOutline.setMindMapURL(mindMapResultVO.getImageUrl());
                    courseOutline.setMindMapEditURL(mindMapResultVO.getEditUrl());
                } else {
                    log.warn("思维导图生成失败或未完成");
                }
            } else {
                log.warn("课程大纲数据无效，跳过思维导图生成");
            }
        } catch (Exception e) {
            log.error("生成思维导图过程中发生异常", e);
        }
        return courseOutline;
    }

    /**
     * 验证课程大纲数据是否有效
     * @param outline 课程大纲对象
     * @return 是否有效
     */
    private boolean isValidCourseOutline(CourseOutline outline) {
        // 检查课程大纲的核心内容是否有效
        if (outline == null) {
            return false;
        }

        // 检查教学内容是否为空
        if (outline.getTeachingContent() == null || outline.getTeachingContent().isEmpty()) {
            return false;
        }

        // 检查是否包含默认的错误信息
        String errorText = "未检索到对应内容，请联系人工客服";

        // 检查关键字段是否包含错误信息
        if (outline.getTeachingObjectives() != null &&
                outline.getTeachingObjectives().contains(errorText)) {
            return false;
        }

        if (outline.getTeachingRequirements() != null &&
                outline.getTeachingRequirements().contains(errorText)) {
            return false;
        }

        return true;
    }

    /**
     * 根据小节名字生成讲义
     * @param sectionName 小节名称
     * @param sessionId 对话id
     * @param format 输出格式 (Markdown/Word/HTML)
     * @return 讲义url
     */
    public String GenerateHandout(String sectionName, String sessionId, String format){
        log.info("开始生成讲义并保存，会话ID：{}，小节名称：{}", sessionId, sectionName);

        // 使用流式生成方法获取内容
        Flux<String> contentFlux = streamGenerateHandoutContent(sectionName, sessionId, format);

        // 收集所有内容
        String content = contentFlux.collectList()
                .map(chunks -> String.join("", chunks))
                .block(); // 同步等待所有内容

        log.info("讲义内容生成完成，长度：{}", content != null ? content.length() : 0);

        // 生成文件名，根据format确定扩展名
        String extension;
        switch (format.toUpperCase()) {
            case "WORD":
                extension = ".docx";
                break;
            case "HTML":
                extension = ".pdf";
                break;
            case "MARKDOWN":
            default:
                extension = ".md";
                break;
        }
        String fileName = sectionName + extension;
        try {
            // 1. 保存到本地
            String filePath = saveFileContent(content, fileName, format);
            File localFile = new File(filePath);
            log.info("讲义已保存至本地: {}", filePath);

            // 2. 上传本地文件到COS
            String cosUrl = cosUtils.uploadFile(localFile, "handouts");
            log.info("讲义已上传至COS: {}", cosUrl);

            // 3. 使用虚拟线程异步删除本地文件
            Thread.startVirtualThread(() -> {
                try {
                    // 等待一段时间再删除，以确保上传完成
                    Thread.sleep(5000);
                    if (localFile.delete()) {
                        log.info("本地文件已删除: {}", filePath);
                    } else {
                        log.warn("本地文件删除失败: {}", filePath);
                    }
                } catch (Exception e) {
                    log.error("删除本地文件时发生错误: {}", e.getMessage(), e);
                }
            });

            return cosUrl; // 返回COS URL
        } catch (IOException e) {
            log.error("保存讲义文件失败: {}", e.getMessage(), e);
            // 根据实际需求处理异常，例如返回错误信息或抛出自定义异常
            return "Error saving handout: " + e.getMessage();
        }
    }

    /**
     * 流式生成讲义内容
     * @param sectionName 小节名称
     * @param sessionId 对话id
     * @param format 输出格式 (Markdown/Word/HTML)
     * @return 讲义内容的流
     */
    public Flux<String> streamGenerateHandoutContent(String sectionName, String sessionId, String format) {
        log.info("开始流式生成讲义，会话ID：{}，小节名称：{}", sessionId, sectionName);

        String chapterGenerateHandout = GenerateHandoutPrompt.TEACHER_PROMPT;

        // 为大模型构建包含格式要求的用户提示
        String userPrompt = sectionName;
        if (!ObjectUtil.isEmpty(format)) {
            userPrompt = sectionName + "\n请以 " + format + " 格式生成内容。";
        }

        // 使用Stream API返回流式结果
        return chatClient
                .prompt()
                .system(chapterGenerateHandout)
                .user(userPrompt)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 20))
                .advisors(new MyLoggerAdvisor())
                .advisors(loveAppRagCloudAdvisor)
                .tools(allTools)
                .stream()
                .content();
    }

    /**
     * 将内容保存到文件
     * @param content 字符串内容
     * @param fileName 文件名 (例如: "linear_algebra_chapter_1.md")
     * @param format 文件格式 (用于记录或未来可能的特定处理，当前主要影响文件名)
     * @return 保存的文件路径
     * @throws IOException 如果文件操作失败
     */
    private String saveFileContent(String content, String fileName, String format) throws IOException {
        // 定义讲义保存的目录，可以从配置中读取或硬编码
        // 如果使用 FileConstant.FILE_SAVE_DIR
        String handoutsDir = FileConstant.FILE_SAVE_DIR + "/handouts";

        Path directoryPath = Paths.get(handoutsDir);
        // 创建目录 (如果不存在)
        if (!Files.exists(directoryPath)) {
            Files.createDirectories(directoryPath);
            log.info("创建讲义目录: {}", directoryPath.toAbsolutePath());
        }

        Path filePath = directoryPath.resolve(fileName);

        // 将内容写入文件 (UTF-8 编码)
        // For .docx, this direct byte writing might not be appropriate if the 'content' is not already a valid docx byte stream.
        // If 'content' for Word is a special format (e.g., base64 encoded docx), you'd decode it here.
        // For now, assuming 'content' is raw bytes or text suitable for direct writing.
        Files.write(filePath, content.getBytes(StandardCharsets.UTF_8));

        return filePath.toAbsolutePath().toString();
    }


    public String doChatWithMcp(String message, String chatId) {
        ChatResponse response = chatClient
                .prompt()
                .user(message)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                // 开启日志，便于观察效果
                .advisors(new MyLoggerAdvisor())
                .tools(allTools)
                .call()
                .chatResponse();
        String content = response.getResult().getOutput().getText();
        log.info("content: {}", content);
        return content;
    }

    /**
     * 实验设计
     * @param Title 实验标题
     * @param sessionId 对话id
     * @param ExperimentalContent 实验内容
     * @param SubmitContent 实验提交内容
     * @return md文本
     */
    public ExperimentalDesign ExperimentalDesign(String Title, String sessionId, String ExperimentalContent, String SubmitContent, String format){
        log.info("开始生成实验设计并保存，会话ID：{}，实验标题：{}", sessionId, Title);

        // 使用流式生成方法获取内容
        Flux<String> contentFlux = streamExperimentalDesignContent(Title, sessionId, ExperimentalContent, SubmitContent, format);

        // 收集所有内容
        String content = contentFlux.collectList()
                .map(chunks -> String.join("", chunks))
                .block(); // 同步等待所有内容

        log.info("实验设计内容生成完成，长度：{}", content != null ? content.length() : 0);

        // 生成文件名，根据format确定扩展名
        String extension;
        switch (format.toUpperCase()) {
            case "WORD":
                extension = ".docx";
                break;
            case "HTML":
                extension = ".pdf";
                break;
            case "MARKDOWN":
            default:
                extension = ".md";
                break;
        }
        ExperimentalDesign experimentalDesign = new ExperimentalDesign();
        experimentalDesign.setExperimentalContent(content);

        String fileName = Title + extension;
        try {
            // 1. 保存到本地
            String filePath = saveFileContent(content, fileName, format);
            File localFile = new File(filePath);
            log.info("实验已保存至本地: {}", filePath);

            // 2. 上传本地文件到COS
            String cosUrl = cosUtils.uploadFile(localFile, "experiments");
            log.info("实验已上传至COS: {}", cosUrl);

            // 3. 使用虚拟线程异步删除本地文件
            Thread.startVirtualThread(() -> {
                try {
                    // 等待一段时间再删除，以确保上传完成
                    Thread.sleep(5000);
                    if (localFile.delete()) {
                        log.info("本地文件已删除: {}", filePath);
                    } else {
                        log.warn("本地文件删除失败: {}", filePath);
                    }
                } catch (Exception e) {
                    log.error("删除本地文件时发生错误: {}", e.getMessage(), e);
                }
            });

            experimentalDesign.setExperimentalFilePath(cosUrl);
            return experimentalDesign; // 返回包含COS URL的对象
        } catch (IOException e) {
            log.error("保存实验文件失败: {}", e.getMessage(), e);
            // 根据实际需求处理异常，例如返回错误信息或抛出自定义异常
            experimentalDesign.setExperimentalFilePath("Error saving experiment: " + e.getMessage());
            return experimentalDesign;
        }
    }

    /**
     * 流式生成实验设计内容
     * @param Title 实验标题
     * @param sessionId 对话id
     * @param ExperimentalContent 实验内容
     * @param SubmitContent 实验提交内容
     * @param format 输出格式 (Markdown/Word/HTML)
     * @return 实验设计内容的流
     */
    public Flux<String> streamExperimentalDesignContent(String Title, String sessionId, String ExperimentalContent, String SubmitContent, String format) {
        log.info("开始流式生成实验设计，会话ID：{}，实验标题：{}", sessionId, Title);

        String userPrompt = labAssistantPrompt.SYSTEM_PROMPT;

        // 使用Stream API返回流式结果
        return chatClient
                .prompt()
                .system(userPrompt)
                .user("实验标题:"+Title + "\n" + "实验课程讲义:" + ExperimentalContent + "\n" + "实验应该提交的内容:" + SubmitContent + "\n"+  "请以 " + format + " 形式生成内容。")
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 20))
                .advisors(new MyLoggerAdvisor())
                // 在流式生成中不使用RAG，避免模板处理错误
                .tools(allTools)
                .stream()
                .content();
    }


    /**
     * 课堂互动问答与研讨题设计
     * @param sessionId 对话id
     * @param handoutContent 讲义内容
     * @return 互动问答结果
     */
    public InteractiveQAResultVO ClassroomInteractiveQA(String sessionId, String handoutContent, String title){
        log.info("开始生成课堂互动问答并解析，会话ID：{}，标题：{}", sessionId, title);

        // 使用流式生成方法获取内容
        Flux<String> contentFlux = streamClassroomInteractiveQAContent(sessionId, handoutContent, title);

        // 收集所有内容
        String jsonContent = contentFlux.collectList()
                .map(chunks -> String.join("", chunks))
                .block(); // 同步等待所有内容

        log.info("课堂互动问答内容生成完成，长度：{}", jsonContent != null ? jsonContent.length() : 0);

        try {
            // 处理可能的前缀和后缀
            if (jsonContent.contains("```json")) {
                jsonContent = jsonContent.substring(jsonContent.indexOf("```json") + 7);
                jsonContent = jsonContent.substring(0, jsonContent.indexOf("```"));
            }

            // 使用ObjectMapper解析JSON
            ObjectMapper objectMapper = new ObjectMapper();
            InteractiveQAResultVO result = objectMapper.readValue(jsonContent, InteractiveQAResultVO.class);

            // 设置标题
            result.setTitle(title);

            return result;
        } catch (Exception e) {
            log.error("解析互动问题JSON失败: {}", e.getMessage(), e);
            // 创建一个包含错误信息的返回对象
            InteractiveQAResultVO errorResult = new InteractiveQAResultVO();
            errorResult.setTitle(title);
            errorResult.setQuestions(new ArrayList<>());

            // 直接返回原始文本作为一个问题
            InteractiveQuestionVO errorQuestion = new InteractiveQuestionVO();
            errorQuestion.setQuestionType("解析错误");
            errorQuestion.setQuestionContent("JSON解析失败，原始内容：");
            errorQuestion.setStandardAnswer(jsonContent);
            errorResult.getQuestions().add(errorQuestion);

            return errorResult;
        }
    }

    /**
     * 流式生成课堂互动问答内容
     * @param sessionId 对话id
     * @param handoutContent 讲义内容
     * @param title 讲义标题
     * @return 互动问答内容的流
     */
    public Flux<String> streamClassroomInteractiveQAContent(String sessionId, String handoutContent, String title) {
        log.info("开始流式生成课堂互动问答，会话ID：{}，标题：{}", sessionId, title);

        String prompt = ClassroomInteractiveQAPrompt.SYSTEM_PROMPT;

        // 使用Stream API返回流式结果
        return chatClient
                .prompt()
                .system(prompt)
                .user("课程讲义标题:" + title + "\n" + "课程讲义内容:" + handoutContent)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 20))
                .advisors(new MyLoggerAdvisor())
                // 在流式生成中不使用RAG，避免模板处理错误
                .tools(allTools)
                .stream()
                .content();
    }


    /**
     * 时间轴总结
     * @param sessionId 对话id
     * @param textContent 音频文件转文本内容
     * @return 时间轴总结结果
     */
    public TimelineSummaryVO TimelineSummary(String sessionId, String textContent) {
        String timelineSummaryPrompt = TimelineSummaryPrompt.TIMELINE_SUMMARY_PROMPT;
        ChatResponse chatResponse = chatClient
                .prompt()
                .system(timelineSummaryPrompt)
                .user("音频解析结果" + textContent)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 20))
                // 开启日志，便于观察效果
                .advisors(new MyLoggerAdvisor())
                .tools(allTools)
                .call()
                .chatResponse();

        String jsonContent = chatResponse.getResult().getOutput().getText();

        // 解析JSON内容
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            // 创建返回对象
            TimelineSummaryVO summaryVO = new TimelineSummaryVO();

            // 提取JSON内容，处理可能包含的代码块标记
            jsonContent = extractJsonContent(jsonContent);

            // 解析大模型返回的JSON
            JsonNode rootNode = objectMapper.readTree(jsonContent);

            // 提取fullText
            if (rootNode.has("fullText")) {
                summaryVO.setFullText(rootNode.get("fullText").asText(""));
            }

            // 提取timeContentMap
            if (rootNode.has("timeContentMap")) {
                Map<String, String> timeContentMap = new LinkedHashMap<>();
                JsonNode mapNode = rootNode.get("timeContentMap");

                Iterator<Map.Entry<String, JsonNode>> fields = mapNode.fields();
                while (fields.hasNext()) {
                    Map.Entry<String, JsonNode> entry = fields.next();
                    timeContentMap.put(entry.getKey(), entry.getValue().asText());
                }

                summaryVO.setTimeContentMap(timeContentMap);
            }

            return summaryVO;

        } catch (Exception e) {
            log.error("解析时间轴总结内容失败: {}", e.getMessage(), e);
            // 返回空对象并记录错误
            TimelineSummaryVO errorResult = new TimelineSummaryVO();
            errorResult.setFullText("解析失败: " + e.getMessage());
            return errorResult;
        }
    }

    /**
     * 从大模型返回的内容中提取JSON
     * 处理可能返回的带有markdown代码块的JSON内容
     */
    private String extractJsonContent(String content) {
        // 检查是否有JSON代码块标记
        if (content.contains("```json")) {
            Pattern pattern = Pattern.compile("```json\\s*\\n?(.*?)\\n?```", Pattern.DOTALL);
            Matcher matcher = pattern.matcher(content);
            if (matcher.find()) {
                return matcher.group(1).trim();
            }
        }

        // 检查是否有普通代码块标记
        if (content.contains("```")) {
            Pattern pattern = Pattern.compile("```\\s*\\n?(.*?)\\n?```", Pattern.DOTALL);
            Matcher matcher = pattern.matcher(content);
            if (matcher.find()) {
                return matcher.group(1).trim();
            }
        }

        // 没有代码块标记，直接返回原内容
        return content.trim();
    }


    /**
     * 教学反思
     * @param sessionId 对话id
     * @param textContent 音频文件转文本内容
     * @return 教学反思结果
     */
    public String TeachingReflection(String sessionId, String textContent) {
        String teachingReflectionAssistantPrompt = TeachingReflectionAssistantPrompt.TEACHING_REFLECTION_ASSISTANT_PROMPT;
        ChatResponse chatResponse = chatClient
                .prompt()
                .system(teachingReflectionAssistantPrompt)
                .user(textContent)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 20))
                // 开启日志，便于观察效果
                .advisors(new MyLoggerAdvisor())
                .tools(allTools)
                .call()
                .chatResponse();
        return chatResponse.getResult().getOutput().getText();
    }

    /**
     * 教学计划
     * @param sessionId 对话id
     * @param textContent 音频文件转文本内容
     * @return 教学计划结果
     */
    public String TeachingPlan(String sessionId, String textContent) {
        log.info("开始生成教学计划并汇总，会话ID：{}", sessionId);

        // 使用流式生成方法获取内容
        Flux<String> contentFlux = streamTeachingPlanContent(sessionId, textContent);

        // 收集所有内容
        String content = contentFlux.collectList()
                .map(chunks -> String.join("", chunks))
                .block(); // 同步等待所有内容

        log.info("教学计划内容生成完成，长度：{}", content != null ? content.length() : 0);

        return content;
    }

    /**
     * 流式生成教学计划内容
     * @param sessionId 对话id
     * @param textContent 教学大纲内容
     * @return 教学计划内容的流
     */
    public Flux<String> streamTeachingPlanContent(String sessionId, String textContent) {
        log.info("开始流式生成教学计划，会话ID：{}", sessionId);

        String generateTeachingPlan = TeachingPlanPrompt.GENERATE_TEACHING_PLAN;

        // 使用Stream API返回流式结果
        return chatClient
                .prompt()
                .system(generateTeachingPlan)
                .user(textContent)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 20))
                .advisors(new MyLoggerAdvisor())
                // 在流式生成中不使用RAG，避免模板处理错误
                .tools(allTools)
                .stream()
                .content();
    }

    /**
     * 智能生成试卷 - 多线程多智能体并行生成
     * @param sessionId 会话ID
     * @param requirements 试卷生成要求（包含科目、难度、题型结构等）
     * @return 试卷JSON字符串（将被解析为ExamPaperVO对象）
     */
    public String ExamPaperGeneration(String sessionId, String requirements) {
        log.info("开始多线程生成试卷，会话ID：{}，要求长度：{}", sessionId, requirements.length());

        try {
            // 解析试卷结构和要求
            Map<String, Object> examRequirements = parseExamRequirements(requirements);
            List<Map<String, Object>> sections = extractSections(requirements);

            if (sections.isEmpty()) {
                log.warn("未能从要求中识别出试卷部分，将使用单线程生成");
                return generateFullExamPaper(sessionId, requirements);
            }

            // 创建线程池
            ExecutorService executorService = Executors.newFixedThreadPool(
                    Math.min(sections.size(), Runtime.getRuntime().availableProcessors())
            );

            // 为每个部分创建一个任务
            List<Future<String>> sectionFutures = new ArrayList<>();
            for (Map<String, Object> section : sections) {
                sectionFutures.add(executorService.submit(() ->
                        generateExamSection(sessionId, requirements, section)
                ));
            }

            // 收集所有部分的结果
            List<String> sectionResults = new ArrayList<>();
            for (Future<String> future : sectionFutures) {
                try {
                    sectionResults.add(future.get());
                } catch (Exception e) {
                    log.error("获取试卷部分生成结果失败", e);
                }
            }

            // 关闭线程池
            executorService.shutdown();

            // 合并所有部分为完整试卷
            String combinedExamPaper = combineExamSections(examRequirements, sectionResults);
            log.info("多线程试卷生成成功，JSON长度: {}", combinedExamPaper.length());

            return combinedExamPaper;

        } catch (Exception e) {
            log.error("多线程生成试卷失败", e);
            // 失败时回退到单线程生成
            log.info("尝试回退到单线程生成试卷");
            return generateFullExamPaper(sessionId, requirements);
        }
    }

    /**
     * 单线程生成完整试卷（回退方案）
     */
    private String generateFullExamPaper(String sessionId, String requirements) {
        // 高质量试卷生成提示词
        String examPaperGenerationPrompt = "你是一位资深的教育评估与试卷设计专家，拥有丰富的教学经验和试题研发能力。" +
                "请根据以下要求设计一份高质量、标准化的考试试卷。\n\n" +
                "设计原则：\n" +
                "1. 试题内容应符合学科标准与教育大纲，保持概念准确性和学术严谨性\n" +
                "2. 试题难度分布合理，由浅入深，能够全面评估学生的知识掌握程度\n" +
                "3. 问题表述清晰、无歧义，措辞精准专业\n" +
                "4. 答案解析详细且具有教学价值，包含思路分析、关键知识点和常见错误提示\n" +
                "5. 选择题选项设计合理，干扰项有迷惑性但不存在多解情况\n" +
                "6. 主观题评分标准细化，明确给分点\n\n" +

                "请直接输出JSON格式的试卷，确保每道题都包含完整的题目内容、答案和详细解析。JSON结构如下：\n" +
                "{\"title\":试卷标题,\"subject\":科目,\"duration\":时长,\"totalScore\":总分,\"examInstructions\":考试说明," +
                "\"sections\":[{\"sectionTitle\":\"部分标题\",\"instructions\":\"部分说明\",\"sectionScore\":分值,\"questions\":[" +
                "{\"questionNumber\":\"题号\",\"content\":\"题目内容\",\"score\":分值,\"options\":{选项},\"type\":\"题型\"}]}]," +
                "\"answerGuide\":[{\"questionNumber\":\"题号\",\"correctAnswer\":\"答案\",\"explanation\":\"解析，包含思路、知识点和常见错误\"}]}";

        ChatResponse chatResponse = chatClient
                .prompt()
                .system(examPaperGenerationPrompt)
                .user("请根据以下要求设计一份高质量考试试卷（含详细答案和解析）：\n\n" + requirements)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId))
                .call()
                .chatResponse();

        String content = chatResponse.getResult().getOutput().getText();
        return extractJsonContent(content);
    }

    /**
     * 生成试卷的单个部分
     */
    private String generateExamSection(String sessionId, String generalRequirements, Map<String, Object> sectionInfo) {
        try {
            String sectionType = (String) sectionInfo.get("sectionType");
            // 为特定题型创建专业化提示词
            String sectionPrompt = "你是一位专精于" + sectionType + "试题设计的教育专家。你深入理解该题型的特点、考查目标和评分标准。\n\n" +
                    "请根据以下要求，设计高质量的" + sectionType + "试题：\n" +
                    "1. 试题应符合学科标准与课程大纲要求，知识点覆盖全面且准确\n" +
                    "2. 试题难度适中且梯度合理，能够区分不同能力水平的学生\n" +
                    "3. 问题表述严谨清晰，没有歧义或误导\n" +
                    "4. 每道题必须包含详细的参考答案和解析，帮助学生理解答题思路和知识点\n";

            // 针对不同题型添加特定指导
            if (sectionType.contains("选择题")) {
                sectionPrompt += "5. 选项设计合理，干扰项具有合理的迷惑性，但不应有多解情况\n" +
                        "6. 选项分布均衡，避免答案规律\n";
            } else if (sectionType.contains("填空题")) {
                sectionPrompt += "5. 设计明确的答案空间，空白处应该是关键知识点或核心概念\n" +
                        "6. 答案应唯一明确，避免有多种可能的表达\n";
            } else if (sectionType.contains("简答题") || sectionType.contains("论述题")) {
                sectionPrompt += "5. 问题应能引导学生进行分析、综合或评价等高阶思维\n" +
                        "6. 评分标准应明确列出主要给分点和评分依据\n";
            } else if (sectionType.contains("计算题") || sectionType.contains("应用题")) {
                sectionPrompt += "5. 问题情境应贴近实际，数据合理\n" +
                        "6. 解析应包含完整的计算过程和公式使用说明\n";
            }

            sectionPrompt += "\n请将设计的试题按以下JSON格式输出：\n" +
                    "{\"sectionTitle\":\"" + sectionType + "\",\"instructions\":\"部分说明\",\"sectionScore\":分值,\"questions\":[" +
                    "{\"questionNumber\":\"题号\",\"content\":\"题目内容\",\"score\":分值,\"options\":{选项},\"type\":\"" + sectionType + "\"}]," +
                    "\"answers\":[{\"questionNumber\":\"题号\",\"correctAnswer\":\"答案\",\"explanation\":\"详细解析\"}]}";

            // 构建该部分专属的要求
            String sectionRequirements;
            try {
                sectionRequirements = "总体试卷要求：" + generalRequirements + "\n\n" +
                        sectionType + "部分要求：" + new ObjectMapper().writeValueAsString(sectionInfo);
            } catch (JsonProcessingException e) {
                log.error("序列化部分信息失败", e);
                sectionRequirements = "总体试卷要求：" + generalRequirements + "\n\n" +
                        sectionType + "部分要求：" + sectionInfo.toString();
            }

            // 使用新的会话ID，确保不同智能体之间不会互相干扰
            String sectionSessionId = sessionId + "-" + sectionType + "-" + UUID.randomUUID().toString();

            ChatResponse chatResponse = chatClient
                    .prompt()
                    .system(sectionPrompt)
                    .user("请根据以下要求，设计高质量的" + sectionType + "试题（含详细答案和解析）：\n\n" + sectionRequirements)
                    .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, sectionSessionId))
                    .call()
                    .chatResponse();

            String content = chatResponse.getResult().getOutput().getText();
            return this.extractJsonContent(content);
        } catch (Exception e) {
            log.error("生成试卷部分失败", e);
            throw new RuntimeException("生成试卷部分失败: " + e.getMessage());
        }
    }

    /**
     * 解析试卷总体要求
     */
    private Map<String, Object> parseExamRequirements(String requirements) {
        Map<String, Object> result = new HashMap<>();

        // 提取基本信息
        Pattern titlePattern = Pattern.compile("标题：([^\n]+)");
        Matcher titleMatcher = titlePattern.matcher(requirements);
        if (titleMatcher.find()) {
            result.put("title", titleMatcher.group(1).trim());
        }

        Pattern subjectPattern = Pattern.compile("科目：([^\n]+)");
        Matcher subjectMatcher = subjectPattern.matcher(requirements);
        if (subjectMatcher.find()) {
            result.put("subject", subjectMatcher.group(1).trim());
        }

        Pattern durationPattern = Pattern.compile("考试时长：(\\d+)分钟");
        Matcher durationMatcher = durationPattern.matcher(requirements);
        if (durationMatcher.find()) {
            result.put("duration", Integer.parseInt(durationMatcher.group(1)));
        }

        Pattern totalScorePattern = Pattern.compile("总分：(\\d+)分");
        Matcher totalScoreMatcher = totalScorePattern.matcher(requirements);
        if (totalScoreMatcher.find()) {
            result.put("totalScore", Integer.parseInt(totalScoreMatcher.group(1)));
        }

        return result;
    }

    /**
     * 从要求中提取各部分信息
     */
    private List<Map<String, Object>> extractSections(String requirements) {
        List<Map<String, Object>> sections = new ArrayList<>();

        // 提取试卷结构部分
        String structureRegex = "试卷结构：\\s*\\n((?:[^\\n]*\\n)+)";
        Pattern structurePattern = Pattern.compile(structureRegex);
        Matcher structureMatcher = structurePattern.matcher(requirements);

        if (structureMatcher.find()) {
            String structureSection = structureMatcher.group(1);
            Pattern sectionPattern = Pattern.compile("- ([^：]+)：(\\d+)题，(\\d+)分(?:，要求：([^\\n]*))?");
            Matcher sectionMatcher = sectionPattern.matcher(structureSection);

            while (sectionMatcher.find()) {
                Map<String, Object> section = new HashMap<>();
                section.put("sectionType", sectionMatcher.group(1).trim());
                section.put("questionCount", Integer.parseInt(sectionMatcher.group(2)));
                section.put("sectionScore", Integer.parseInt(sectionMatcher.group(3)));

                if (sectionMatcher.groupCount() >= 4 && sectionMatcher.group(4) != null) {
                    section.put("requirements", sectionMatcher.group(4).trim());
                }

                sections.add(section);
            }
        }

        return sections;
    }

    /**
     * 合并所有部分为完整试卷
     */
    private String combineExamSections(Map<String, Object> examRequirements, List<String> sectionResults) {
        try {
            ObjectMapper objectMapper = new ObjectMapper();

            // 创建完整试卷结构
            Map<String, Object> examPaper = new HashMap<>();
            examPaper.putAll(examRequirements);

            List<Map<String, Object>> combinedSections = new ArrayList<>();
            List<Map<String, Object>> combinedAnswers = new ArrayList<>();

            // 处理每个部分的JSON结果
            for (String sectionJson : sectionResults) {
                try {
                    Map<String, Object> sectionData = objectMapper.readValue(sectionJson, Map.class);

                    // 添加部分到试卷
                    if (sectionData.containsKey("sectionTitle")) {
                        // 保留问题部分
                        Map<String, Object> sectionCopy = new HashMap<>();
                        sectionCopy.put("sectionTitle", sectionData.get("sectionTitle"));
                        sectionCopy.put("instructions", sectionData.get("instructions"));
                        sectionCopy.put("sectionScore", sectionData.get("sectionScore"));
                        sectionCopy.put("questions", sectionData.get("questions"));

                        combinedSections.add(sectionCopy);
                    }

                    // 收集答案
                    if (sectionData.containsKey("answers")) {
                        combinedAnswers.addAll((List<Map<String, Object>>) sectionData.get("answers"));
                    }
                } catch (JsonProcessingException e) {
                    log.error("解析部分JSON失败: {}", sectionJson, e);
                }
            }

            examPaper.put("sections", combinedSections);
            examPaper.put("answerGuide", combinedAnswers);

            return objectMapper.writeValueAsString(examPaper);

        } catch (JsonProcessingException e) {
            log.error("合并试卷部分失败", e);
            throw new RuntimeException("合并试卷部分失败: " + e.getMessage());
        }
    }

    /**
     * 流式智能生成试卷
     * @param sessionId 会话ID
     * @param requirements 试卷生成要求（包含科目、难度、题型结构等）
     * @return 试卷JSON字符串流（将被解析为ExamPaperVO对象）
     */
    public Flux<String> streamExamPaperGeneration(String sessionId, String requirements) {
        log.info("开始流式生成试卷，会话ID：{}，要求长度：{}", sessionId, requirements.length());

        // 使用高质量试卷生成提示词
        String examPaperGenerationPrompt = "你是一位资深的教育评估与试卷设计专家，拥有丰富的教学经验和试题研发能力。" +
                "请根据以下要求设计一份高质量、标准化的考试试卷。\n\n" +
                "设计原则：\n" +
                "1. 试题内容应符合学科标准与教育大纲，保持概念准确性和学术严谨性\n" +
                "2. 试题难度分布合理，由浅入深，能够全面评估学生的知识掌握程度\n" +
                "3. 问题表述清晰、无歧义，措辞精准专业\n" +
                "4. 答案解析详细且具有教学价值，包含思路分析、关键知识点和常见错误提示\n" +
                "5. 选择题选项设计合理，干扰项有迷惑性但不存在多解情况\n" +
                "6. 主观题评分标准细化，明确给分点\n\n" +

                "请直接输出JSON格式的试卷，确保每道题都包含完整的题目内容、答案和详细解析。JSON结构如下：\n" +
                "{\"title\":试卷标题,\"subject\":科目,\"duration\":时长,\"totalScore\":总分,\"examInstructions\":考试说明," +
                "\"sections\":[{\"sectionTitle\":\"部分标题\",\"instructions\":\"部分说明\",\"sectionScore\":分值,\"questions\":[" +
                "{\"questionNumber\":\"题号\",\"content\":\"题目内容\",\"score\":分值,\"options\":{选项},\"type\":\"题型\"}]}]," +
                "\"answerGuide\":[{\"questionNumber\":\"题号\",\"correctAnswer\":\"答案\",\"explanation\":\"解析，包含思路、知识点和常见错误\"}]}";

        // 使用Stream API直接返回流式结果
        return chatClient
                .prompt()
                .system(examPaperGenerationPrompt)
                .user("请根据以下要求设计一份高质量考试试卷（含详细答案和解析）：\n\n" + requirements)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, sessionId))
                .advisors(loveAppRagCloudAdvisor)
                .stream()
                .content();
    }

}
